using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using Microsoft.Xna.Framework.Net;
using Microsoft.Xna.Framework.Storage;
using System.IO;
using System.Globalization;

namespace CharacterAnimationEditor
{
    public class SkeletonSerializer
    {
        public void Save(Context context, Timeline timeline, string name)
        {
            TextWriter tw = new StreamWriter("anim_" + name + ".txt");
            foreach (var item in timeline.keyframes)
            {
                SaveKeyframe(item, tw);
            }

            tw.Close();
        }

        private void SaveKeyframe(KeyFrame kf, TextWriter tw)
        {
            tw.WriteLine("Keyframe=" + kf.Time.ToString(CultureInfo.InvariantCulture));
            SaveSkeleton(kf.Pose, tw);
        }

        public void Save(Context context, Skeleton skeleton, string name)
        {
            TextWriter tw = new StreamWriter("skel" + name + ".txt");
            SaveSkeleton(skeleton, tw);

            // close the stream
            tw.Close();
        }

        private void SaveSkeleton(Skeleton skeleton, TextWriter tw)
        {
            tw.WriteLine("Root=" + skeleton.Body.Position.X.ToString(CultureInfo.InvariantCulture) + " " + skeleton.Body.Position.Y.ToString(CultureInfo.InvariantCulture));
            WriteBone(tw, skeleton.Body);
        }

        private void WriteBone(TextWriter tw, Bone bone)
        {
            tw.WriteLine(bone.Name + "=" + bone.LocalRotation.ToString(CultureInfo.InvariantCulture));

            foreach (var item in bone.Children)
            {
                WriteBone(tw, item);
            }
        }


        public Timeline LoadAnimation(Context context, string name)
        {
            Timeline timeline = new Timeline(context);
            timeline.keyframes.Clear();

            TextReader tr = new StreamReader("anim_" + name + ".txt");
            string line;
            while ((line = tr.ReadLine()) != null)
            {
                if (line.Contains("Keyframe="))
                {
                    float time = float.Parse(line.Split('=')[1], CultureInfo.InvariantCulture);
                    KeyFrame kf = new KeyFrame(context, time);
                    timeline.keyframes.Add(kf);
                }
                else if (line.Contains("Root="))
                {
                    Vector2 position = ParseVector2(line.Split('=')[1]);

                    Skeleton s = new Skeleton(context, position, "SkeletonRig.txt");
                    timeline.keyframes[timeline.keyframes.Count - 1].Pose = s;
                }
                else
                {
                    Skeleton s = timeline.keyframes[timeline.keyframes.Count - 1].Pose;
                    string bone = line.Split('=')[0];
                    float rot = float.Parse(line.Split('=')[1], CultureInfo.InvariantCulture);
                    Bone b = GetBone(bone, s.Body);
                    b.LocalRotation = rot;
                }
            }

            tr.Close();
            timeline.SetCurrentKeyFrame(context, timeline.keyframes[0]);
            timeline.UpdateTimeRange();
            return timeline;
        }


        public Skeleton Load(Context context, string name)
        {
            TextReader tr = new StreamReader("skel" + name + ".txt");

            Vector2 position = ParseVector2(tr.ReadLine().Split('=')[1]);

            Skeleton s = new Skeleton(context, position, "SkeletonRig.txt");

            string line;
            while ((line = tr.ReadLine()) != null)
            {
                string bone = line.Split('=')[0];
                float rot = float.Parse(line.Split('=')[1]);
                Bone b = GetBone(bone, s.Body);
                b.LocalRotation = rot;
            }

            return s;
        }

        private Bone GetBone(string name, Bone bone)
        {
            if (bone.Name == name)
            {
                return bone;
            }

            foreach (var item in bone.Children)
            {
                Bone b = GetBone(name, item);
                if (b != null)
                {
                    return b;
                }
            }

            return null;
        }



        private Vector2 ParseVector2(string p)
        {
            return new Vector2(
                float.Parse(p.Split()[0], CultureInfo.InvariantCulture),
                float.Parse(p.Split()[1], CultureInfo.InvariantCulture));
        }

    }
}
